package cn.htsyb.synergy.maker.engine.impl;

import cn.htsyb.synergy.maker.config.Maker;
import cn.htsyb.synergy.maker.config.meta.Template;
import cn.htsyb.synergy.maker.engine.ITmplEngine;
import cn.htsyb.synergy.maker.model.MetaTable;
import cn.htsyb.synergy.maker.util.FileUtil;
import cn.htsyb.synergy.maker.util.StreamUtil;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Properties;

public class VelocityEngine implements ITmplEngine {
    private final static Logger logger = LoggerFactory.getLogger(VelocityEngine.class);
    Maker maker = null;
    Template template = null;

    org.apache.velocity.app.VelocityEngine velocityEngine;
    Properties properties;

    public VelocityEngine(Maker config) {
        initEngine(config);
    }

    @Override
    public String getEngineName() {
        return "velocity";
    }

    @Override
    public String getTmplEndSuffix() {
        return ".vm";
    }

    @Override
    public void generate(List<MetaTable> tableList) {
        logger.info("将处理{}张数据库表", (tableList == null ? 0 : tableList.size()));
        try {
            if(tableList!=null&&tableList.size()>0) {
                List globalTmplFile = FileUtil.listFile(template.getGlobalPrefixPath(), template.getEndSuffix());
                generateGlobal(tableList, globalTmplFile);
                List tmplFile = FileUtil.listFile(template.getPrefixPath(), template.getEndSuffix());
                generateTable(tableList, tmplFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void generateGlobal(List<MetaTable> tableList, List<File> tmplFileList) {
        if(tableList!=null&&tableList.size()>0) {
            VelocityContext velocityContext = new VelocityContext();
            velocityContext.put("tableList", tableList);
            velocityContext.put("maker", maker);
            tmplFileList.forEach(tmplFile -> {
                try {
                    String writerFilePath = makeWriterFilePath(tmplFile, template.getGlobalPrefixPath(), template.getGlobalExportPath());
                    File writerFile = handleFilePathVar(velocityContext, writerFilePath);
                    FileUtil.existAndCreate(writerFile);
                    handleFileContentVar(velocityContext, tmplFile, writerFile);
                    logger.info("文件写入到'{}'成功", writerFile.getPath());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    protected void generateTable(List<MetaTable> tableList, List<File> tmplFileList) {
        tableList.forEach(metaTable -> {
            try {
                logger.info("开始处理数据库{}表", metaTable.getTableName());

                VelocityContext velocityContext = new VelocityContext();
                velocityContext.put("table", metaTable);
                velocityContext.put("maker", maker);

                tmplFileList.forEach(tmplFile -> {
                    try {
                        String writerFilePath = makeWriterFilePath(tmplFile, template.getPrefixPath(), template.getExportPath());
                        File writerFile = handleFilePathVar(velocityContext, writerFilePath);
                        FileUtil.existAndCreate(writerFile);
                        handleFileContentVar(velocityContext, tmplFile, writerFile);
                        logger.info("文件写入到'{}'成功", writerFile.getPath());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
                logger.info("结束处理数据库{}表", metaTable.getTableName());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });
    }

    protected String makeWriterFilePath(File tmplFile, String prefixPath, String exportPath) {
        String shortPath = tmplFile.getPath()
                .replace(prefixPath, "")
                .replace(template.getEndSuffix(), "");
        String outPutFilePath = exportPath +
                File.separatorChar +
                maker.getCompile().getCurrentPackage() +
                shortPath;
        //修正路径变量偏差问题
        outPutFilePath = outPutFilePath.replace("\\", "/");
        return outPutFilePath;
    }

    protected File handleFilePathVar(VelocityContext velocityContext, String filePath) throws IOException {
        //处理文件路径上的模板字符
        StringWriter pathWriter = new StringWriter();
        velocityEngine.evaluate(velocityContext, pathWriter, "", filePath);
        File file = new File(pathWriter.toString());
        return file;

    }

    protected void handleFileContentVar(VelocityContext velocityContext, File readFilePath, File writerFilePath) throws IOException {
        try (FileWriter fileWriter = new FileWriter(writerFilePath, false)) {

            String templateContent = StreamUtil.readContent(new FileInputStream(readFilePath), Charset.defaultCharset())
                    //处理模板中空行字符问题
                    .replaceAll("[ ]*(#|#if|#else|#elseif|#end|#set|#foreach)", "$1");
            velocityEngine.evaluate(velocityContext, fileWriter, "", templateContent);
        }
    }

    @Override
    public void initEngine(Maker config) {
        this.maker = config;
        this.template = config.getTemplate();
        properties = new Properties();
        //设置模板的加载方式为文件
        properties.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, template.getExportPath());
        //支持中文处理
        properties.setProperty(Velocity.ENCODING_DEFAULT, Charset.defaultCharset().name());
        properties.setProperty(Velocity.INPUT_ENCODING, Charset.defaultCharset().name());
        velocityEngine = new org.apache.velocity.app.VelocityEngine(properties);
    }
}
